package cn.juque.common.abstracts;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.juque.common.base.BaseConstants;
import cn.juque.common.base.BaseOperator;
import cn.juque.common.constants.AuthScopeTypeEnum;
import cn.juque.common.constants.MessageEnum;
import cn.juque.common.constants.StringConstants;
import cn.juque.common.constants.YesOrNoEnum;
import cn.juque.common.exception.AppException;

import java.util.List;
import java.util.stream.Collectors;

/**
 * @author nuoka
 * @version 1.0.0
 * <li>数据权限管理</li>
 * @date 2021/12/13 23:28
 **/
public abstract class AbstractRoleDataManagement {

    protected static final String NO_DATA_SCRIPT = "1 <> 1";

    protected static final String ALL_DATA_SCRIPT = "1 = 1";

    /**
     * 获取数据权限的控制脚本
     *
     * @param operator      操作人
     * @param scopeTypeEnum 数据范围
     * @return 脚本
     */
    public String getAuthDataScript(BaseOperator operator, AuthScopeTypeEnum scopeTypeEnum) {
        return this.getAuthDataScript(operator, scopeTypeEnum, YesOrNoEnum.NO, CollUtil.newArrayList(), CollUtil.newArrayList());
    }

    /**
     * 获取数据权限的控制脚本
     *
     * @param operator      操作人
     * @param scopeTypeEnum 数据范围
     * @param includeSub    是否包含下级，仅对机构有效
     * @param orgIdList     自定义机构的指定机构id
     * @param userIdList    自定义用户的指定用户id
     * @return 脚本
     */
    public String getAuthDataScript(BaseOperator operator, AuthScopeTypeEnum scopeTypeEnum, YesOrNoEnum includeSub, List<String> orgIdList, List<String> userIdList) {
        // 系统管理员可以访问所有数据
        if (this.isAdmin(operator)) {
            return ALL_DATA_SCRIPT;
        }
        if (!Boolean.TRUE.equals(this.checkRole(operator.getRoleIdList()))) {
            return NO_DATA_SCRIPT;
        }
        String script;
        switch (scopeTypeEnum) {
            case ORG:
                script = getOrgScript(operator, includeSub);
                break;
            case USER:
                // 用户数据
                script = getUserScript(operator);
                break;
            case CUSTOM_ORG:
                script = getCustomOrgScript(operator, orgIdList);
                break;
            case CUSTOM_USER:
                script = getCustomUserScript(operator, userIdList);
                break;
            default:
                // 抛出异常
                throw new AppException(MessageEnum.PARAM_ERROR.getCode(), "数据权限类型非法");
        }
        return script;
    }

    /**
     * 获取机构范围的脚本
     *
     * @param operator   操作人
     * @param includeSub 是否包含下级
     * @return 脚本
     */
    protected abstract String getOrgScript(BaseOperator operator, YesOrNoEnum includeSub);

    /**
     * 获取员工本人的数据权限脚本
     *
     * @param operator 操作人
     * @return 脚本
     */
    protected String getUserScript(BaseOperator operator) {
        return "CREATE_USER_ID = " + operator.getOperatorId();
    }

    /**
     * 获取指定机构范围的权限脚本
     *
     * @param operator 操作人
     * @return 脚本
     */
    protected String getCustomOrgScript(BaseOperator operator, List<String> orgIdList) {
        if (CollUtil.isEmpty(orgIdList)) {
            return NO_DATA_SCRIPT;
        }
        String template = "{}CREATE_ORG_ID IN ({})";
        String orgIdArray = orgIdList.stream().distinct()
                .map(f -> StringConstants.SINGLE_QUOTATION + f + StringConstants.SINGLE_QUOTATION).collect(Collectors.joining());
        return CharSequenceUtil.format(template, this.tableAlias(), orgIdArray);
    }

    /**
     * 获取指定员工的权限脚本
     *
     * @param operator       操作人
     * @param employeeIdList 指定的员工id列表
     * @return 脚本
     */
    protected String getCustomUserScript(BaseOperator operator, List<String> employeeIdList) {
        if (CollUtil.isEmpty(employeeIdList)) {
            return NO_DATA_SCRIPT;
        }
        String template = "{}CREATE_USER_ID IN ({})";
        String employeeIdArray = employeeIdList.stream().distinct()
                .map(f -> StringConstants.SINGLE_QUOTATION + f + StringConstants.SINGLE_QUOTATION).collect(Collectors.joining());
        return CharSequenceUtil.format(template, this.tableAlias(), employeeIdArray);
    }

    /**
     * 校验ID是否存在
     *
     * @param roleIdList 角色ID列表
     * @return true / false
     */
    protected abstract Boolean checkRole(List<String> roleIdList);

    /**
     * 表别名
     *
     * @return string
     */
    protected String tableAlias() {
        return CharSequenceUtil.EMPTY;
    }

    private boolean isAdmin(BaseOperator baseOperator) {
        return baseOperator.getRoleIdList().contains(BaseConstants.ROLE_ADMIN);
    }
}
